/************************************************************************
Copyright 2003, 2004, 2005, 2006, 2007, 2008 Grid Technology Research Center,
National Institute of Advanced Industrial Science and Technology.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
************************************************************************/

package jp.aist.gtrc.plus.scheduler.util;

import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;

import org.apache.log4j.Logger;

import jp.aist.gtrc.plus.scheduler.node.NodeInfo;


public class Filter<V> {

	private final List<Checker<V>> checkers = new LinkedList<Checker<V>>();
	private final List<Checker<V>> oneTimeCheckers = new LinkedList<Checker<V>>();
	private static final int GET_ALL_OF_PASSED = Integer.MAX_VALUE;
	protected static final  Logger logger = Logger.getLogger(Filter.class);

	public void addChecker(Checker<V> checker){

		/*
		 * 'checker' remains after calling filter()
		 */
		checkers.add(checker);

	}

	private void removeChecker(Checker<V> checker){

		checkers.remove(checker);

	}

	public void addOneTimeChecker(Checker<V> checker){

		/*
		 * 'checker' will be removed after calling filter()
		 */
		addChecker(checker);
		oneTimeCheckers.add(checker);

	}

	private Collection<V> doFilter2(Collection<V> objs, int min, int max){

		if ((min < 0) || (objs == null) || (min > max))
			return null;
		if ((objs.size() < min) && (max != GET_ALL_OF_PASSED))
			return null;

		/*
		 * We want to use faster okObjs.contains(o),
		 * so use LinkedHashSet, not LinkedList.
		 */
		Collection<V> okObjs = new LinkedHashSet<V>();

		for (V o : objs) {
			boolean passed = true;
			for (Checker<V> checker : checkers) {
				if (checker.isOK(o, okObjs) == false) {
					if (o instanceof NodeInfo) {
						NodeInfo node = (NodeInfo)o;
						logger.debug(node.getName() + " is dropped by "
								+ checker.getClass().getCanonicalName());
					}
					passed = false;
					break;
				}
			}
			if (passed == true) {
				okObjs.add(o);
				if (okObjs.size() == max) {
					// return all check passed objects
					return okObjs;
				}
			}
		}

		int size = okObjs.size();
		if (size == 0) {
			// always return null, all objects are not passed
			return null;
		} else if (size >= min) {
			// min <= size < max
			return okObjs;
		} else {
			// size < min
			return null;
		}

	}

	private Collection<V> doFilter(Collection<V> objs, int min, int max){

		try {
			return doFilter2(objs, min, max);
		} finally {
			// remove one time only checker from 'checkers'.
			for (Checker<V> c : oneTimeCheckers) {
				removeChecker(c);
			}
			oneTimeCheckers.clear();
		}

	}

	public Collection<V> filter(Collection<V> objs, int num){

		return doFilter(objs, num, num);

	}

	public Collection<V> filter(Collection<V> objs, int min, int max){

		return doFilter(objs, min, max);

	}

	public Collection<V> filter(Collection<V> objs) {

		return filter(objs, 0, GET_ALL_OF_PASSED);

	}

}
